// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string>
#include <sys/system_properties.h>
#include <fstream>
#include <map>
#include "CaeConfigManage.h"
#include "CaeTransIP.h"
#include "CaeLogConfig.h"
#include "CaeInitCert.h"
#include "../cae_service/CaeEngineControl.h"

using namespace std;
static const string SIGN_CHECK_URL;
static const string EVENT_NOTIFY_URL;
static const string HEARTBEAT_URL;
static const string HEARTBEAT_INTERVAL = "60";

// 云手机参数
static uint32_t HEIGHT_MAX;
static uint32_t WIDTH_MAX;
static uint32_t FPS_MAX;
static bool isSupportH264;
static bool isSupportH265;
static bool isSupportYuv;
static bool isSupportHardEncode;
static bool isSupportSoftEncode;

// 池化调度elb的ip和端口
static const string POOL_SCHEDULING_ELB_IP;
static const uint16_t POOL_SCHEDULING_ELB_PORT = 0;

// 可选配置文件参数相关信息
static std::map<std::string, std::string> caeConfig = {};
// 后端鉴权url地址
const string KEY_SIGN_CHECK_URL = "sign_check_url";
// 后端上报接入和退出的url地址
const string KEY_EVENT_NOTIFY_URL = "event_notify_url";
// 后端心跳url地址
const string KEY_HEARTBEAT_URL = "heartbeat_url";
// 编码池elb ip
const string KEY_POOL_SCHEDULING_ELB_IP = "pool_scheduling_elb_ip";
// 编码池elb port
const string KEY_POOL_SCHEDULING_ELB_PORT = "pool_scheduling_elb_port";
// 是否开启远程输入法功能
const string KEY_ENABLE_REMOTE_IME = "enable_remote_ime";
// 是否开启自定义数据通道功能
const string KEY_ENABLE_DATA_CHANNEL = "enable_data_channel";
// 是否开启虚拟仿真设备功能
const string KEY_ENABLE_VIRTUAL_DEVICE = "enable_virtual_device";
// 强制设置音视频码率参数
const string KEY_OVERRIDE_BITRATE = "override_bitrate";
// 强制设置音视频帧率参数
const string KEY_OVERRIDE_FPS = "override_fps";
// 是否开启RTSA
const string KEY_RTSA_ENABLE = "rtsa_enable";
// RTSA分配的appid
const string KEY_RTSA_APPID = "rtsa_appid";
// RTSA分配的appkey
const string KEY_RTSA_APPKEY = "rtsa_appkey";
// RTSA接入房间号
const string KEY_RTSA_ROOMID = "rtsa_roomid";
// RTSA接入用户号
const string KEY_RTSA_USERID = "rtsa_userid";
// RTSA接入端是H5还是Native
const string KEY_RTSA_NATIVE = "rtsa_native";


// 云手机实际物理分辨率
static const uint32_t HARDWARE_HEIGHT = 1920;
static const uint32_t HARDWARE_WIDTH = 1080;

// 监听ip port
static const string LISTEN_IP = "127.0.0.1";
static const uint16_t LISTEN_PORT_APP = 7000;
static const uint16_t LISTEN_PORT_H5 = 7001;

// SSL安全通信所需证书路径
static const string CA_CERT_PATH = "/data/cloudAppEngine/CAE_ca.crt";
static const string CERT_PATH = "/data/cloudAppEngine/CAE_server.crt";
static const string PRIV_KEY_PATH = "/data/cloudAppEngine/CAE_server.key";
static const string CERT_USER_DATA;

// 可选配置文件路径
static const string CAE_CONFIG_PATH = "/data/cloudAppEngine/CaeConfig.ini";

// 基本时间周期，单位为ms
static const int BASE_TIME = 250;

// 基本超时周期数
static const int OUT_TIMES = 4;

// 握手超时周期数，超时时间为 HANDSHAKE_TIMES * OUT_TIMES * BASE_TIME，即为5s
static const int HANDSHAKE_TIMES = 5;

// 暂停超时周期数，超时时间为 PAUSE_TIMES * OUT_TIMES * BASE_TIME，即为60s
static const int PAUSE_TIMES = 60;

// 断链超时周期数，超时时间为 DISCONNECT_TIMES * OUT_TIMES * BASE_TIME，即为30s
static const int DISCONNECT_TIMES = 30;

// 无触控超时周期数，超时时间为 MAX_NOTOUCH_TIMES * OUT_TIMES * BASE_TIME，即60s
static const int NOTOUCH_TIMES = 60;


CaeConfigManage::CaeConfigManage() = default;

CaeConfigManage::~CaeConfigManage() = default;

void CaeConfigManage::SetConfig()
{
    LOGD("App listen port is %d, H5 listen port is %d. ", LISTEN_PORT_APP, LISTEN_PORT_H5);
    LOGI("BaseTime: %d, outTimes: %d, maxPauseTimes: %d, maxDisconnectTimes: %d, maxHandShakeTimes: %d", BASE_TIME,
         OUT_TIMES, PAUSE_TIMES, DISCONNECT_TIMES, HANDSHAKE_TIMES);

    InitMediaFeatures();
    if (access(CAE_CONFIG_PATH.c_str(), F_OK) != 0) {
        return;
    }
    CaeConfigManage::ReadConfig(CAE_CONFIG_PATH.c_str());
    LOGI("Cae setConfig done.");
}

void CaeConfigManage::InitMediaFeatures()
{
    const char* mediaFeatures = CaeEngineControl::GetInstance().GetMediaFeatures();
    cJSON *root = cJSON_Parse(mediaFeatures);
    WIDTH_MAX = cJSON_GetObjectItem(root, "Width_MAX")->valueint;
    HEIGHT_MAX = cJSON_GetObjectItem(root, "Height_MAX")->valueint;
    FPS_MAX = cJSON_GetObjectItem(root, "FPS_MAX")->valueint;
    isSupportH264 = cJSON_GetObjectItem(root, "H264")->valueint == 1;
    isSupportH265 = cJSON_GetObjectItem(root, "H265")->valueint == 1;
    isSupportYuv = cJSON_GetObjectItem(root, "YUV")->valueint == 1;
    isSupportHardEncode = cJSON_GetObjectItem(root, "HardEncode")->valueint == 1;
    isSupportSoftEncode = cJSON_GetObjectItem(root, "SoftEncode")->valueint == 1;
    LOGI("WIDTH_MAX : %d, HEIGHT_MAX : %d, FPS_MAX : %d, isSupportH264 : %d, isSupportH265 : %d,"
         " isSupportYuv : %d, isSupportHardEncode : %d, isSupportSoftEncode : %d",
         WIDTH_MAX, HEIGHT_MAX, FPS_MAX, isSupportH264, isSupportH265, isSupportYuv, isSupportHardEncode, isSupportSoftEncode);
    cJSON_Delete(root);
}

void CaeConfigManage::ReadConfig(const char *filename)
{
    LOGI("Begin to read cae config.");
    ifstream file(filename);
    if (!file.is_open()) {
        LOGE("File: %s can not open.", filename);
        return;
    }
    string line;
    while (getline(file, line)) {
        if (reinterpret_cast<const char *>(line[0]) == "#" || line.empty()) {
            continue;
        }
        size_t pos = line.find('=');
        if (pos != string::npos) {
            string key = line.substr(0, pos);
            string value = line.substr(pos + 1);
            caeConfig[key] = value;
        }
    }
    file.close();
}

uint32_t CaeConfigManage::GetListenIp()
{
    return TransIP(LISTEN_IP.c_str());
}

uint16_t CaeConfigManage::GetListenPortApp()
{
    return LISTEN_PORT_APP;
}

uint16_t CaeConfigManage::GetListenPortH5()
{
    return LISTEN_PORT_H5;
}

uint32_t CaeConfigManage::GetPauseTimes()
{
    return PAUSE_TIMES;
}

uint32_t CaeConfigManage::GetHandShakeTimes()
{
    return HANDSHAKE_TIMES;
}

uint32_t CaeConfigManage::GetDisconnectTimes()
{
    return DISCONNECT_TIMES;
}

uint32_t CaeConfigManage::GetNoTouchTimes()
{
    return NOTOUCH_TIMES;
}

uint32_t CaeConfigManage::GetOutTimes()
{
    return OUT_TIMES;
}

uint32_t CaeConfigManage::GetBaseTime()
{
    return BASE_TIME;
}

const string &CaeConfigManage::GetSignCheckUrl()
{
    return caeConfig.count(KEY_SIGN_CHECK_URL) ? caeConfig[KEY_SIGN_CHECK_URL] : SIGN_CHECK_URL;
}

const string &CaeConfigManage::GetEventNotifyUrl()
{
    return caeConfig.count(KEY_EVENT_NOTIFY_URL) ? caeConfig[KEY_EVENT_NOTIFY_URL] : EVENT_NOTIFY_URL;
}

const string &CaeConfigManage::GetHeartbeatUrl()
{
    return caeConfig.count(KEY_HEARTBEAT_URL) ? caeConfig[KEY_HEARTBEAT_URL] : HEARTBEAT_URL;
}

const string &CaeConfigManage::GetHeartbeatInterval()
{
    return HEARTBEAT_INTERVAL;
}

bool CaeConfigManage::EnableSignCheck()
{
    return GetSignCheckUrl().length() > 0;
}

bool CaeConfigManage::EnableEventNotify()
{
    return GetEventNotifyUrl().length() > 0;
}

bool CaeConfigManage::EnableHeartbeatNotify()
{
    return GetHeartbeatUrl().length() > 0;
}

bool CaeConfigManage::EnableRemoteIme()
{
    if (!caeConfig.count(KEY_ENABLE_REMOTE_IME)) {
        return true;
    }
    try {
        uint16_t enable = std::stoi(caeConfig[KEY_ENABLE_REMOTE_IME]);
        return enable > 0;
    } catch (const std::invalid_argument& e) {
        LOGE("Enable remote ime config is invalid.");
        return true;
    } catch (const std::out_of_range& e) {
        LOGE("Enable remote ime config is out of range.");
        return true;
    }
}

bool CaeConfigManage::EnableDataChannel()
{
    if (!caeConfig.count(KEY_ENABLE_DATA_CHANNEL)) {
        return false;
    }
    try {
        uint16_t enable = std::stoi(caeConfig[KEY_ENABLE_DATA_CHANNEL]);
        return enable > 0;
    } catch (const std::invalid_argument& e) {
        LOGE("Enable data channel config is invalid.");
        return false;
    } catch (const std::out_of_range& e) {
        LOGE("Enable data channel config is out of range.");
        return false;
    }
}

bool CaeConfigManage::EnableVirtualDevice()
{
    if (!caeConfig.count(KEY_ENABLE_VIRTUAL_DEVICE)) {
        return true;
    }
    try {
        uint16_t enable = std::stoi(caeConfig[KEY_ENABLE_VIRTUAL_DEVICE]);
        return enable > 0;
    } catch (const std::invalid_argument& e) {
        LOGE("Enable virturl device config is invalid.");
        return true;
    } catch (const std::out_of_range& e) {
        LOGE("Enable virturl device config is out of range.");
        return true;
    }
}

int CaeConfigManage::GetOverrideBitrate()
{
    if (!caeConfig.count(KEY_OVERRIDE_BITRATE)) {
        return -1;
    }
    try {
        int bitrate = std::stoi(caeConfig[KEY_OVERRIDE_BITRATE]);
        return bitrate;
    } catch (const std::invalid_argument& e) {
        LOGE("override bitrate config is invalid.");
        return -1;
    } catch (const std::out_of_range& e) {
        LOGE("override bitrate config is out of range.");
        return -1;
    }
}

bool CaeConfigManage::IsOverrideBitrate()
{
    int bitrate = GetOverrideBitrate();
    return bitrate >= 100000 && bitrate <= 10000000;
}

int CaeConfigManage::GetOverrideFPS()
{
    if (!caeConfig.count(KEY_OVERRIDE_FPS)) {
        return -1;
    }
    try {
        int fps = std::stoi(caeConfig[KEY_OVERRIDE_FPS]);
        return fps;
    } catch (const std::invalid_argument& e) {
        LOGE("override fps config is invalid.");
        return -1;
    } catch (const std::out_of_range& e) {
        LOGE("override fps config is out of range.");
        return -1;
    }
}

bool CaeConfigManage::IsOverrideFPS()
{
    int fps = GetOverrideFPS();
    return fps >= 10 && fps <= FPS_MAX && GetOverrideFPS() % 10 == 0;
}

uint32_t GetPropertyIntValue(const char* key) {
    uint32_t result;
    char *value = new char[CHAR_SIZE];
    int len = __system_property_get(key, value);
    if (len < 1) {
        LOGE("Failed to get phone id. ");
        result = UINT32_MAX;
    } else {
        result = std::strtol(value, nullptr, 10);
    }
    delete[] value;
    return result;
}

uint32_t CaeConfigManage::GetHardwareHeight()
{
    return HEIGHT_MAX;
};

uint32_t CaeConfigManage::GetHardwareWidth()
{
    return WIDTH_MAX;
}

const string &CaeConfigManage::GetCaCertPath()
{
    return CA_CERT_PATH;
}

const string &CaeConfigManage::GetCertPath()
{
    return CERT_PATH;
}

const string &CaeConfigManage::GetPrivKeyPath()
{
    return PRIV_KEY_PATH;
}

const string &CaeConfigManage::GetCertUserData()
{
    return CERT_USER_DATA;
}

uint32_t CaeConfigManage::GetFps()
{
    return FPS_MAX;
}

bool CaeConfigManage::IsSupportH264()
{
    return isSupportH264;
}

bool CaeConfigManage::IsSupportH265()
{
    return isSupportH265;
}

bool CaeConfigManage::IsSupportYuv()
{
    return isSupportYuv;
}


bool CaeConfigManage::IsSupportHardEncode()
{
    return isSupportHardEncode;
}


bool CaeConfigManage::IsSupportSoftEncode()
{
    return isSupportSoftEncode;
}

int CaeConfigManage::GetLogLevel()
{
    return ANDROID_LOG_INFO;
}

const string &CaeConfigManage::GetPoolSchedulingElbIp()
{
    return caeConfig.count(KEY_POOL_SCHEDULING_ELB_IP) ? caeConfig[KEY_POOL_SCHEDULING_ELB_IP] : POOL_SCHEDULING_ELB_IP;
}

uint16_t CaeConfigManage::GetPoolSchedulingElbPort()
{
    if (!caeConfig.count(KEY_POOL_SCHEDULING_ELB_PORT)) {
        LOGI("Pool scheduling elb port uses default value.");
        return POOL_SCHEDULING_ELB_PORT;
    }
    try {
        uint16_t port = std::stoi(caeConfig[KEY_POOL_SCHEDULING_ELB_PORT]);
        return port;
    } catch (const std::invalid_argument& e) {
        LOGE("Pool scheduling elb port is invalid.");
        return POOL_SCHEDULING_ELB_PORT;
    } catch (const std::out_of_range& e) {
        LOGE("Pool scheduling elb port is out of range.");
        return POOL_SCHEDULING_ELB_PORT;
    }
}

string CaeConfigManage::GetRTSAAppId()
{
    return caeConfig.count(KEY_RTSA_APPID) ? caeConfig[KEY_RTSA_APPID] : "";
}

string CaeConfigManage::GetRTSAAppKey()
{
    return caeConfig.count(KEY_RTSA_APPKEY) ? caeConfig[KEY_RTSA_APPKEY] : "";
}

string CaeConfigManage::GetRTSAUserId()
{
    return caeConfig.count(KEY_RTSA_USERID) ? caeConfig[KEY_RTSA_USERID] : "";
}

string CaeConfigManage::GetRTSARoomId()
{
    return caeConfig.count(KEY_RTSA_ROOMID) ? caeConfig[KEY_RTSA_ROOMID] : "";
}

uint32_t CaeConfigManage::GetRTSAEnable()
{
	return caeConfig.count(KEY_RTSA_ENABLE) ? std::stoi(caeConfig[(KEY_RTSA_ENABLE)]) : 0;
}

uint32_t CaeConfigManage::GetRTSANative()
{
    return caeConfig.count(KEY_RTSA_NATIVE) ? std::stoi(caeConfig[(KEY_RTSA_NATIVE)]) : 0;
}